home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 06 - 1990 / 06.12 Dec 90 / dissMask Source / dissMask.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-08-23  |  6.8 KB  |  152 lines  |  [TEXT/KAHL]

  1. /*    dissMask.c -- Copyright © 1990 by Michael S. Morton.  All rights reserved.
  2.  
  3.         History:
  4.             23-Aug-90    -    MM    -    First public version.
  5.  
  6.         Enhancements needed:
  7.             •    Can CopyMask be used with transfer modes with side effects (e.g., additive)?
  8.                     If so, we should erase the bitmap before setting each new set of bits.
  9. */
  10.  
  11. #include "dissMask.h"
  12.  
  13. /*    Internal prototypes: */
  14. static void round2 (short *i);
  15.  
  16. /*    Masks to generate the pseudo-random sequence.  The
  17.         table runs 0…32, but only elements 2…32 are valid. */
  18. static unsigned long seqMasks [ /* 0…32 */ ] =
  19. {    0x0, 0x0, 0x03, 0x06, 0x0C, 0x14, 0x30, 0x60, 0xB8, 0x0110, 0x0240, 0x0500, 0x0CA0,
  20.     0x1B00, 0x3500, 0x6000, 0xB400, 0x00012000, 0x00020400, 0x00072000, 0x00090000, 0x00140000,
  21.     0x00300000, 0x00400000, 0x00D80000, 0x01200000, 0x03880000, 0x07200000, 0x09000000,
  22.     0x14000000, 0x32800000, 0x48000000, 0xA3000000
  23. };
  24.  
  25. extern Boolean dissMaskInit (srcRect, info)
  26.     Rect *srcRect;                                                /* INPUT: bounds of source rectangle */
  27.     register dissMaskInfo *info;                    /* OUTPUT: state-of-the-world for mask */
  28. {    
  29.     /*    Copy the client’s source rectangle, then normalize it to (0,0) for simplicity. */
  30.     info->maskRect = *srcRect;                        /* copy it… */
  31.     OffsetRect (& info->maskRect,                    /* …and normalize it… */
  32.         -info->maskRect.left, -info->maskRect.top); /* …to (0,0) at the top left */
  33.  
  34.     /*    Round it up to a power of two in each dimension for the bitmap’s bounds.  This
  35.             speeds up the dissolve considerably by removing bounds checking.  Also, ensure
  36.             that the width of the bitmap is a multiple of two bytes, or 16 bits. */
  37.     info->maskMap.bounds = info->maskRect;    /* start by copying the client’s bounds */
  38.     round2 (& info->maskMap.bounds.bottom); /* now round both extents… */
  39.     round2 (& info->maskMap.bounds.right); /* …up to powers of two */
  40.     if (info->maskMap.bounds.right < 16)    /* too small to be a bitmap? */
  41.         info->maskMap.bounds.right = 16;        /* yep: round it up */
  42.  
  43.     /*    Compute total number of pixels in the mask bitmap; initialize the countdown counter. */
  44.     info->pixLeft = info->maskMap.bounds.bottom * (long) info->maskMap.bounds.right;
  45.  
  46.     /*    Figure the magic mask to be used in the dissMaskNext() loop: */
  47.     {    register short log2 = 0;                        /* log base-two of pixel count */
  48.         register unsigned long ct;                    /* working copy of pixel count */
  49.  
  50.         ct = info->pixLeft;
  51.         while (ct > 1)                                            /* until log2(ct) == 0 */
  52.             {    ct >>= 1; ++log2; }                            /* …shift it down one; bump log2 */
  53.  
  54.         /*    Actually, I don’t think either of these (<2 or >32) can happen… */
  55.         if ((log2 < 2) || (log2 > 32))            /* outside of table bounds? */
  56.             return FALSE;                                            /* can’t do this; client should CopyBits() */
  57.         info->seqMask = seqMasks [log2];        /* set up the mask which generates cycle of length 2**log2 */
  58.     }
  59.  
  60.     /*    Because we count iterations, we needn’t watch the sequence element: it can start anywhere. */
  61.     info->seqElement = 1;                                    /* init sequence element to any nonzero value */
  62.  
  63.     /*    Finish filling in the pixmap; handle allocation failure. */
  64.     info->maskMap.rowBytes = info->maskMap.bounds.right / 8;
  65.     info->maskMap.baseAddr = NewPtrClear (info->pixLeft / 8); /* allocate data for bitmap */
  66.     if (! info->maskMap.baseAddr)                    /* allocation failed? */
  67.         return FALSE;                                                /* tell client [should we clear MemErr?] */
  68.  
  69.     --info->pixLeft;                                            /* kludge: one element is done outside loop */
  70.     return TRUE;                                                    /* client can continue */
  71. }                                                                                /* end of dissMaskInit () */
  72.  
  73. extern void dissMaskNext (info, steps)
  74.     register dissMaskInfo *info;                    /* UPDATE: state-of-the-world for mask */
  75.     register unsigned long steps;                    /* INPUT: number of steps to take */
  76. {    register unsigned long element, mask;    /* for use in asm{} */
  77.     register void *baseAddr;                            /* for use in asm{} */
  78.  
  79.     if (steps == 0) steps = 1;                        /* keep things sane */
  80.     if (steps > info->pixLeft)                        /* more steps than we need? */
  81.         steps = info->pixLeft;                            /* yes: just go ’til the end */
  82.     info->pixLeft -= steps;                                /* debit this before we trash “steps” */
  83.  
  84.     element = info->seqElement;                        /* move these… */
  85.     mask = info->seqMask;                                    /* …memory-based variables… */
  86.     baseAddr = info->maskMap.baseAddr;        /* …into registers for asm {} */
  87.  
  88.     --steps;                                                            /* set up counter to run out at -1, not 0, for DBRA rules */
  89.  
  90.     /*    If all the arithmetic can be done in 16 bits, we do so: */
  91.     if ((info->seqMask & 0xffff) == info->seqMask)
  92.         asm
  93.         {    /*    Sixteen-bit case: “.w” operands and a simple DBRA to wind it up. */
  94.     @loopStart16:
  95.             /*    Set the bit for the current sequence element: */
  96.             move.w    element, D0                                /* copy bit number… */
  97.             move.b    D0, D1                                        /* and make a copy for numbering within a byte */
  98.             lsr.w        #3, D0                                        /* convert bit number to byte number */
  99.             bset        D1, 0(baseAddr, D0.w)            /* set D1’st bit in D0’th byte of contiguous bitmap */
  100.  
  101.             /*    Advance to the next sequence element.  If this element was 1, we’re all done. */
  102.             lsr.w        #1, element                                /* throw out a bit… */
  103.             bcc.s        @skipXOR16                                /* …if it’s only a zero, don’t XOR */
  104.             eor.w        mask, element                            /* if a one-bit fell off, flip mask-bits */
  105.     @skipXOR16:
  106.             dbra        steps, @loopStart16                /* count down steps */
  107.         }
  108.  
  109.     else asm
  110.         {    /*    Thirty-two-bit case: “.l” operands and a SUB.L to follow up the DBRA: */
  111.     @loopStart32:
  112.             /*    Set the bit for the current sequence element: */
  113.             move.l    element, D0                                /* copy bit number… */
  114.             move.b    D0, D1                                        /* and make a copy for numbering within a byte */
  115.             lsr.l        #3, D0                                        /* convert bit number to byte number */
  116.             bset        D1, 0(baseAddr, D0.l)            /* set D1’st bit in D0’th byte of contiguous bitmap */
  117.  
  118.             /*    Advance to the next sequence element.  If this element was 1, we’re all done. */
  119.             lsr.l        #1, element                                /* throw out a bit… */
  120.             bcc.s        @skipXOR32                                /* …if it’s only a zero, don’t XOR */
  121.             eor.l        mask, element                            /* if a one-bit fell off, flip mask-bits */
  122.     @skipXOR32:
  123.             dbra        steps, @loopStart32                /* count down low word of steps */
  124.             sub.l        #0x00010000, steps                /* low word ran out: check high word */
  125.             bpl.s        @loopStart32                            /* still ≥ 0: loop some more */
  126.         }
  127.  
  128.     info->seqElement = element;                        /* update sequence element from asm{}’s changes */
  129.  
  130.     if (! info->pixLeft)                                    /* all general pixels copied? */
  131.         asm                                                                    /* yes: there’s a special case */
  132.         {    bset    #0, (baseAddr)                            /* element 0 never comes up, so set bit #0 in byte #0 */
  133.         }
  134. }                                                                                /* end of dissMaskNext () */
  135.  
  136. extern void dissMaskFinish (info)
  137.     register dissMaskInfo *info;                    /* UPDATE: struct to clean up */
  138. {    DisposPtr (info->maskMap.baseAddr);
  139.     info->maskMap.baseAddr = 0L;                    /* lights on for safety */
  140. }                                                                                /* end of dissMaskFinish () */
  141.  
  142. /*    round2 -- Round a value up to the next power of two. */
  143. static void round2 (i)
  144.     register short *i;
  145. {    register short result;
  146.  
  147.     result = 1;
  148.     while (result < *i)
  149.         result <<= 1;
  150.     *i = result;
  151. }                                                                                /* end of round2 () */
  152.